#ifndef PHYSICSABLE_H
#define PHYSICSABLE_H

#include <list>
#include <map>

#include "gameObject.h"

enum PhysicsType {NONE, BLOCK, BULLET, LASERBEAM, SHIP};

//STUPID LINKING ERROR FIX IS IN: ship.cpp

class Physicsable : virtual public GameObject {
	private:
		cpBody* body_;
		std::list<cpShape*> shapes_;
		PhysicsType physicsType_;

		static cpSpace* space_;
		static std::map<PhysicsType, std::map<PhysicsType, bool> > collisionMap_;
		static std::map<cpShape*, Physicsable*> shapeMap_;

	public:
		//Make default physicsable: an r=1 circle at the origin of mass 1
		Physicsable() : GameObject() {
			body_ = cpBodyNew(1.0, 1.0);
			shapes_.push_front(cpCircleShapeNew(body_, 1.0, cpvzero));
			cpBodySetMoment(body_, cpMomentForCircle(1.0, 0.0, 0.0, cpvzero));
		}

		//Make shapeless Physicsable: Remeber to add shapes to make this usefull
		Physicsable(PhysicsType type, float mass) {
			body_ = cpBodyNew(mass, 1.0);
			physicsType_ = type;
		}

		virtual ~Physicsable() {}

		inline bool isPhysicsable() {return true;}
		
		inline static int collide(cpShape *a,
								  cpShape *b,
								  cpContact *contacts,
								  int numContacts,
								  cpFloat normal_coef,
								  void *data) {return 0;}

		//Get and set collision space
		inline static cpSpace* getSpace() {return space_;}
		inline static void setSpace(cpSpace* space) {space_ = space;}
				
		//Add poly shape
		inline void addPolyShape(float mass, int numVertii, cpVect* vertii, cpVect offset) {
			cpShape* shape = cpPolyShapeNew(body_, numVertii, vertii, offset);
			shape->collision_type = physicsType_;
			shapes_.push_front(shape);
			shapeMap_[shape] = this;
			cpBodySetMass(body_, body_->m + mass);
			cpBodySetMoment(body_, body_->i + cpMomentForPoly(body_->m, numVertii, vertii, offset));
		}

		inline void addCircleShape(float mass, float radius, cpVect offset) {
			cpShape* shape = cpCircleShapeNew(body_, radius, offset);
			shape->collision_type = physicsType_;
			shapes_.push_front(shape);
			shapeMap_[shape] = this;
			cpBodySetMass(body_, body_->m + mass);
			cpBodySetMoment(body_, body_->i + cpMomentForCircle(body_->m, 0.0, radius, offset));
		}

		//Collision control
		inline void addSpecialCollision(PhysicsType type) {
			if((collisionMap_[physicsType_])[type] == false) {
				(collisionMap_[physicsType_])[type] = true;
				(collisionMap_[type])[physicsType_] = true;
				cpSpaceAddCollisionPairFunc(space_, physicsType_, type, Physicsable::collide, NULL);
			}
		}

		//Getters
		inline cpBody* getBody() {return body_;}
		inline std::list<cpShape*>* getShapes() {return &shapes_;}
		inline PhysicsType getPhysicsType() {return physicsType_;}
};

#endif
